﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Xps;
using System.Windows.Xps.Packaging;
using RG.Common.WPF.Frames;
using RG.Common.WPF.Reporting.XPS_Utils;

namespace RG.Common.WPF.Reporting.Controls
{
    public class ContractViewer : DocumentViewer
    {
        #region object Report
        public static readonly DependencyProperty ReportProperty =
            DependencyProperty.Register("Report", typeof(object), typeof(ContractViewer),
                                        new FrameworkPropertyMetadata(null, new PropertyChangedCallback(UpdateDoc)));

        public object Report
        {
            set{SetValue(ReportProperty, value);}
            get { return GetValue(ReportProperty); }
        }

        #endregion

        #region Size PageSize
        public static readonly DependencyProperty PageSizeProperty =
            DependencyProperty.Register("PageSize", typeof(Size), typeof(ContractViewer),
                                        new FrameworkPropertyMetadata(new Size(96 / 2.54 * 21, 96 / 2.54 * 28.7), new PropertyChangedCallback(UpdateDoc)));

        public Size PageSize
        {
            set{SetValue(PageSizeProperty, value);}
            get { return (Size)GetValue(PageSizeProperty); }
        }

        #endregion

        private List<FixedDocumentSequence> docs;

        protected void UpdateDoc()
        {
            docs = new List<FixedDocumentSequence>();
            if (Report is IEnumerable)
            {
                var pages = (IEnumerable)Report;
                foreach (object page in pages)
                {
                    AddDoc(page, PageSize);
                }
            }
            else
            {
                AddDoc(Report, PageSize);
            }
            Document = docs.Count == 1 ? docs[0] : SplitedDoc(docs);
        }

        protected void AddDoc(object objReport,Size pageSize)
        {
            if (objReport is IReport)
            {
                XpsReport report = ((IReport)objReport).report;
                if (report.DataContext == null)
                    report.DataContext = DataContext;
                docs.Add(GetXPS(report,pageSize).GetFixedDocumentSequence());
            }
            else if ((objReport is Page) && (((Page)objReport).Content is XpsReport))
            {
                var report = (XpsReport)(((Page)objReport).Content);
                if (report.DataContext == null)
                    report.DataContext = DataContext;
                docs.Add(GetXPS(report, pageSize).GetFixedDocumentSequence());
            }
        }

        protected static void UpdateDoc(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var self = o as ContractViewer;
            if (self != null)
                self.UpdateDoc();
        }

        private static int packageID;

        static XpsDocument GetXPS(XpsReport report,Size pageSize)
        {
            var packUri = String.Format("pack://tmped{0}.xps", packageID++);
            var ms = new MemoryStream();
            var package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
            var doc = new XpsDocument(package, CompressionOption.SuperFast, packUri);
            PackageStore.RemovePackage(new Uri(packUri));
            PackageStore.AddPackage(new Uri(packUri), package);

            XpsDocumentWriter xpsWriter = XpsDocument.CreateXpsDocumentWriter(doc);
            xpsWriter.Write(new XpsReportPaginator(report, pageSize));

            return doc;
        }

        static FixedDocumentSequence SplitedDoc(IEnumerable<FixedDocumentSequence> docs)
        {
            if(docs.Count()==0)
                return null;
            var documentRollUp = new RollUpDocument();
            var source = new List<DocumentItem>();
            foreach (var sequence in docs)
            {
                foreach (var docRef in sequence.References)
                {
                    var item = new DocumentItem(docRef.Name, docRef);
                    source.Add(item);
                }
            }

            foreach (var item in source)
            {
                documentRollUp.AddDocument(item.DocumentReference.Source, (item.DocumentReference as IUriContext).BaseUri);
            }
            return documentRollUp.FixedDocumentSequence;
        }
    }
}